package cn.jjaw.command.note.command;

import cn.jjaw.command.note.command.type.TypeHandle;
import cn.jjaw.command.note.command.type.TypeHandles;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * 方法命令
 */
public abstract class MethodCommand extends RegCommandExecute{
    Method commandMethod;
    /**
     * 动态表达式位置列表
     */
    int[] regN;

    /**
     * 类型处理器
     */
    TypeHandle[] typeHandles;


    /**
     * @param commandMethod 方法
     * @param reg 匹配表达式
     */
    public MethodCommand(String[] reg, Method commandMethod) {
        super(reg);
        this.commandMethod = commandMethod;
        commandMethod.setAccessible(true);

        //动态元素位置表
        ArrayList<Integer> arrayList = new ArrayList<>();
        for (int i = 0; i < reg.length; i++) {
            if(reg[i].equals("?")){
                arrayList.add(i);
            }
        }
        regN = new int[arrayList.size()];
        for (int i = 0; i < arrayList.size(); i++) {
            regN[i] = arrayList.get(i);
        }
        //检查动态表达式的个数是否于参数个数匹配
        Type[] types = commandMethod.getGenericParameterTypes();
        if(types.length!=regN.length){
            throw new MethodMismatchingError(
                    "动态参数个数与方法参数个数不匹配，表达式"+
                            Arrays.toString(reg)+
                            "中有"+regN.length+"个'?'方法"+commandMethod+"中有"+types.length+"个参数"
            );
        }
        //加载每个参数对应的类型处理器
        typeHandles = new TypeHandle[types.length];
        for (int i = 0; i < types.length; i++) {
            TypeHandle typeHandle = TypeHandles.get(types[i].getTypeName());
            if(typeHandle==null){
                throw new MethodMismatchingError("找不到"+types[i].getTypeName()+"类型对应的TypeHandle解析器");
            }
            typeHandles[i] = typeHandle;
        }
    }

    /**
     * 调用方法
     * @param command 命令
     * @param o 对象
     */
    public Object invoke(String[] command,Object o) throws InvocationTargetException, IllegalAccessException {
        Object[] objects = new Object[typeHandles.length];
        for (int i = 0; i < objects.length; i++) {
            objects[i] = typeHandles[i].handle(command[regN[i]]);
        }
        return commandMethod.invoke(o,objects);
    }
}
